package util;

import exception.AncException;
import function.AncSFunction;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author Anc
 * @date 2020/4/16
 */
public class AncBeanUtil {

    public static Map<String, String> descripe(Object bean){
        try {
            return BeanUtils.describe(bean);
        } catch (Exception e) {
            throw new AncException("descripe error",e);
        }
    }

    /**
     * 根据getter方法获取javaBean的属性名
     * */
    public static <T> String getBeanNameByGetter(AncSFunction<T> hilifeSFunction){
        if (!hilifeSFunction.getClass().isSynthetic()) {
            throw new AncException("该方法仅能传入 lambda 表达式产生的合成类");
        }

        try {
            SerializedLambda serializedLambda = resolve(hilifeSFunction);

            return resolveFieldName(serializedLambda.getImplMethodName());
        } catch (Exception e) {
            throw new AncException("getBeanNameByGetter error",e);
        }
    }

    // ==============================================私有方法============================================
    /**
     * 通过反序列化转换 lambda 表达式，该方法只能序列化 lambda 表达式，不能序列化接口实现或者正常非 lambda 写法的对象
     *
     * @return 返回解析后的 SerializedLambda
     */
    private static SerializedLambda resolve(Serializable serializable) throws Exception {
        Method method = serializable.getClass().getDeclaredMethod("writeReplace");
        method.setAccessible(Boolean.TRUE);

        return (SerializedLambda) method.invoke(serializable);
    }

    /**
     * 解析 getMethodName -> propertyName
     *
     * @param getMethodName 需要解析的
     * @return 返回解析后的字段名称
     */
    private static String resolveFieldName(String getMethodName) {
        if (getMethodName.startsWith("get")) {
            // 截取get 转为小写
            return firstToLowerCase(getMethodName.substring(3));
        } else if (getMethodName.startsWith("is")) {
            // 截取is 转为小写
            return firstToLowerCase(getMethodName.substring(2));
        }

        throw new AncException("不符合javaBean标准的getter方法 getMethodName="+getMethodName);
    }

    /**
     * 首字母转换小写
     *
     * @param param 需要转换的字符串
     * @return 转换好的字符串
     */
    private static String firstToLowerCase(String param) {
        if(StringUtils.isEmpty(param)){
            return StringUtils.EMPTY;
        }

        return param.substring(0, 1).toLowerCase() + param.substring(1);
    }
}
